home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / utilitys / less_14z / part06 < prev    next >
Internet Message Format  |  1991-07-08  |  45KB

  1. Path: news.larc.nasa.gov!amiga-request
  2. From: amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator)
  3. Subject: v91i132: Less 1.4Z - text pager, Part06/07
  4. Reply-To: rayz@altair.csustan.edu (R. L. Zarling)
  5. Newsgroups: comp.sources.amiga
  6. Message-ID: <comp.sources.amiga.v91i132@ab20.larc.nasa.gov>
  7. References: <comp.sources.amiga.v91i127@ab20.larc.nasa.gov>
  8. Date: 04 Jul 91 17:28:19 GMT
  9. Approved: tadguy@uunet.UU.NET (Tad Guy)
  10. X-Mail-Submissions-To: amiga@uunet.uu.net
  11. X-Post-Discussions-To: comp.sys.amiga.misc
  12.  
  13. Submitted-by: rayz@altair.csustan.edu (R. L. Zarling)
  14. Posting-number: Volume 91, Issue 132
  15. Archive-name: utilities/less-1.4z/part06
  16.  
  17. #!/bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 6 (of 7)."
  24. # Contents:  Less1.4Z/src/regexp.c
  25. # Wrapped by tadguy@ab20 on Thu Jul  4 13:28:16 1991
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'Less1.4Z/src/regexp.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'Less1.4Z/src/regexp.c'\"
  29. else
  30. echo shar: Extracting \"'Less1.4Z/src/regexp.c'\" \(41694 characters\)
  31. sed "s/^X//" >'Less1.4Z/src/regexp.c' <<'END_OF_FILE'
  32. X/*
  33. X * regcomp and regexec -- regsub and regerror are elsewhere
  34. X *
  35. X *      Copyright (c) 1986 by University of Toronto.
  36. X *      Written by Henry Spencer.  Not derived from licensed software.
  37. X *
  38. X *      Permission is granted to anyone to use this software for any
  39. X *      purpose on any computer system, and to redistribute it freely,
  40. X *      subject to the following restrictions:
  41. X *
  42. X *      1. The author is not responsible for the consequences of use of
  43. X *              this software, no matter how awful, even if they arise
  44. X *              from defects in it.
  45. X *
  46. X *      2. The origin of this software must not be misrepresented, either
  47. X *              by explicit claim or by omission.
  48. X *
  49. X *      3. Altered versions must be plainly marked as such, and must not
  50. X *              be misrepresented as being the original software.
  51. X *
  52. X * Beware that some of this code is subtly aware of the way operator
  53. X * precedence is structured in regular expressions.  Serious changes in
  54. X * regular-expression syntax might require a total rethink.
  55. X
  56. X * 10/09/88 - This code was altered by Mark R. Rinfret for compatibility
  57. X * with the Amiga. (mrr@amanpt1.ZONE1.COM)
  58. X * 6/15/91 - Added ANSI prototypes - Ray Zarling (rayz@csustan.EDU)
  59. X */
  60. X#include <stdio.h>
  61. X#include <string.h>
  62. X#include <stdlib.h>
  63. X#include "regexp.h"
  64. X#include "regmagic.h"
  65. X#ifdef AMIGA
  66. X#define exit(x) quit()
  67. X#define regerror(x) error(x)
  68. Xextern void error ( char *s );
  69. Xextern void quit( void );
  70. X#endif
  71. X
  72. X/* Prototypes for functions defined in regexp.c */
  73. X
  74. Xstatic char *reg __PROTO((int paren,
  75. X                          int *flagp));
  76. Xstatic char *regbranch __PROTO((int *flagp));
  77. Xstatic char *regpiece __PROTO((int *flagp));
  78. Xstatic char *regatom __PROTO((int *flagp));
  79. Xstatic char *regnode __PROTO((char op));
  80. Xstatic void regc __PROTO((char b));
  81. Xstatic void reginsert __PROTO((char op,
  82. X                               char *opnd));
  83. Xstatic void regtail __PROTO((char *p,
  84. X                             char *val));
  85. Xstatic void regoptail __PROTO((char *p,
  86. X                               char *val));
  87. Xstatic int regtry __PROTO((regexp *prog,
  88. X                           char *string));
  89. Xstatic int regmatch __PROTO((char *prog));
  90. Xstatic int regrepeat __PROTO((char *p));
  91. Xstatic char *regnext __PROTO((register char *p));
  92. X
  93. X
  94. X
  95. X/*
  96. X * The "internal use only" fields in regexp.h are present to pass info from
  97. X * compile to execute that permits the execute phase to run lots faster on
  98. X * simple cases.  They are:
  99. X *
  100. X * regstart     char that must begin a match; '\0' if none obvious
  101. X * reganch      is the match anchored (at beginning-of-line only)?
  102. X * regmust      string (pointer into program) that match must include, or NULL
  103. X * regmlen      length of regmust string
  104. X *
  105. X * Regstart and reganch permit very fast decisions on suitable starting points
  106. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  107. X * of lines that cannot possibly match.  The regmust tests are costly enough
  108. X * that regcomp() supplies a regmust only if the r.e. contains something
  109. X * potentially expensive (at present, the only such thing detected is * or +
  110. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  111. X * supplied because the test in regexec() needs it and regcomp() is computing
  112. X * it anyway.
  113. X */
  114. X
  115. X/*
  116. X * Structure for regexp "program".  This is essentially a linear encoding
  117. X * of a nondeterministic finite-state machine (aka syntax charts or
  118. X * "railroad normal form" in parsing technology).  Each node is an opcode
  119. X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  120. X * all nodes except BRANCH implement concatenation; a "next" pointer with
  121. X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  122. X * have one of the subtle syntax dependencies:  an individual BRANCH (as
  123. X * opposed to a collection of them) is never concatenated with anything
  124. X * because of operator precedence.)  The operand of some types of node is
  125. X * a literal string; for others, it is a node leading into a sub-FSM.   In
  126. X * particular, the operand of a BRANCH node is the first node of the branch.
  127. X * (NB this is *not* a tree structure:  the tail of the branch connects
  128. X * to the thing following the set of BRANCHes.)  The opcodes are:
  129. X */
  130. X
  131. X/* definition   number  opnd?   meaning */
  132. X#define END     0       /* no   End of program. */
  133. X#define BOL     1       /* no   Match "" at beginning of line. */
  134. X#define EOL     2       /* no   Match "" at end of line. */
  135. X#define ANY     3       /* no   Match any one character. */
  136. X#define ANYOF   4       /* str  Match any character in this string. */
  137. X#define ANYBUT  5       /* str  Match any character not in this string. */
  138. X#define BRANCH  6       /* node Match this alternative, or the next... */
  139. X#define BACK    7       /* no   Match "", "next" ptr points backward. */
  140. X#define EXACTLY 8       /* str  Match this string. */
  141. X#define NOTHING 9       /* no   Match empty string. */
  142. X#define STAR    10      /* node Match this (simple) thing 0 or more times. */
  143. X#define PLUS    11      /* node Match this (simple) thing 1 or more times. */
  144. X#define OPEN    20      /* no   Mark this point in input as start of #n. */
  145. X                        /*      OPEN+1 is number 1, etc. */
  146. X#define CLOSE   30      /* no   Analogous to OPEN. */
  147. X
  148. X/*
  149. X * Opcode notes:
  150. X *
  151. X * BRANCH       The set of branches constituting a single choice are hooked
  152. X *              together with their "next" pointers, since precedence prevents
  153. X *              anything being concatenated to any individual branch.  The
  154. X *              "next" pointer of the last BRANCH in a choice points to the
  155. X *              thing following the whole choice.  This is also where the
  156. X *              final "next" pointer of each individual branch points; each
  157. X *              branch starts with the operand node of a BRANCH node.
  158. X *
  159. X * BACK         Normal "next" pointers all implicitly point forward; BACK
  160. X *              exists to make loop structures possible.
  161. X *
  162. X * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  163. X *              BRANCH structures using BACK.  Simple cases (one character
  164. X *              per match) are implemented with STAR and PLUS for speed
  165. X *              and to minimize recursive plunges.
  166. X *
  167. X * OPEN,CLOSE   ...are numbered at compile time.
  168. X */
  169. X
  170. X/*
  171. X * A node is one char of opcode followed by two chars of "next" pointer.
  172. X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  173. X * value is a positive offset from the opcode of the node containing it.
  174. X * An operand, if any, simply follows the node.  (Note that much of the
  175. X * code generation knows about this implicit relationship.)
  176. X *
  177. X * Using two bytes for the "next" pointer is vast overkill for most things,
  178. X * but allows patterns to get big without disasters.
  179. X */
  180. X#define OP(p)   (*(p))
  181. X#define NEXT(p) (((*((p)+1)&0377)<<8) + *((p)+2)&0377)
  182. X#define OPERAND(p)      ((p) + 3)
  183. X
  184. X/*
  185. X * See regmagic.h for one further detail of program structure.
  186. X */
  187. X
  188. X
  189. X/*
  190. X * Utility definitions.
  191. X */
  192. X#ifndef CHARBITS
  193. X#define UCHARAT(p)      ((int)*(unsigned char *)(p))
  194. X#else
  195. X#define UCHARAT(p)      ((int)*(p)&CHARBITS)
  196. X#endif
  197. X
  198. X#define FAIL(m) { regerror(m); return(NULL); }
  199. X#define ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
  200. X#define META    "^$.[()|?+*\\"
  201. X
  202. X/*
  203. X * Flags to be passed up and down.
  204. X */
  205. X#define HASWIDTH        01      /* Known never to match null string. */
  206. X#define SIMPLE          02      /* Simple enough to be STAR/PLUS operand. */
  207. X#define SPSTART         04      /* Starts with * or +. */
  208. X#define WORST           0       /* Worst case. */
  209. X
  210. X/*
  211. X * Global work variables for regcomp().
  212. X */
  213. Xstatic char *regparse;  /* Input-scan pointer. */
  214. Xstatic int regnpar;             /* () count. */
  215. Xstatic char regdummy;
  216. Xstatic char *regcode;           /* Code-emit pointer; ®dummy = don't. */
  217. Xstatic long regsize;            /* Code size. */
  218. X
  219. X/*
  220. X * Forward declarations for regcomp()'s friends.
  221. X */
  222. X#ifndef STATIC
  223. X#define STATIC  static
  224. X#endif
  225. XSTATIC char *reg();
  226. XSTATIC char *regbranch();
  227. XSTATIC char *regpiece();
  228. XSTATIC char *regatom();
  229. XSTATIC char *regnode();
  230. XSTATIC char *regnext();
  231. XSTATIC void regc();
  232. XSTATIC void reginsert();
  233. XSTATIC void regtail();
  234. XSTATIC void regoptail();
  235. X#ifdef STRCSPN
  236. XSTATIC int strcspn();
  237. X#endif
  238. X
  239. X/*
  240. X - regcomp - compile a regular expression into internal code
  241. X *
  242. X * We can't allocate space until we know how big the compiled form will be,
  243. X * but we can't compile it (and thus know how big it is) until we've got a
  244. X * place to put the code.  So we cheat:  we compile it twice, once with code
  245. X * generation turned off and size counting turned on, and once "for real".
  246. X * This also means that we don't allocate space until we are sure that the
  247. X * thing really will compile successfully, and we never have to move the
  248. X * code and thus invalidate pointers into it.   (Note that it has to be in
  249. X * one piece because free() must be able to free it all.)
  250. X *
  251. X * Beware that the optimization-preparation code in here knows about some
  252. X * of the structure of the compiled regexp.
  253. X */
  254. X#ifdef __STDC__
  255. Xregexp *regcomp (char *exp)
  256. X#else
  257. Xregexp *
  258. Xregcomp(exp)
  259. Xchar *exp;
  260. X#endif
  261. X{
  262. X        register regexp *r;
  263. X        register char *scan;
  264. X        register char *longest;
  265. X        register int len;
  266. X        int flags;
  267. X#ifndef AMIGA
  268. X        extern char *calloc();
  269. X#endif
  270. X
  271. X        if (exp == NULL)
  272. X                FAIL("NULL argument");
  273. X
  274. X        /* First pass: determine size, legality. */
  275. X        regparse = exp;
  276. X        regnpar = 1;
  277. X        regsize = 0L;
  278. X        regcode = ®dummy;
  279. X        regc(MAGIC);
  280. X        if (reg(0, &flags) == NULL)
  281. X                return(NULL);
  282. X
  283. X        /* Small enough for pointer-storage convention? */
  284. X        if (regsize >= 32767L)          /* Probably could be 65535L. */
  285. X                FAIL("regexp too big");
  286. X
  287. X        /* Allocate space. */
  288. X        r = (regexp *)calloc(1,sizeof(regexp) + (unsigned)regsize);
  289. X        if (r == NULL)
  290. X                FAIL("out of space");
  291. X
  292. X        /* Second pass: emit code. */
  293. X        regparse = exp;
  294. X        regnpar = 1;
  295. X        regcode = r->program;
  296. X        regc(MAGIC);
  297. X        if (reg(0, &flags) == NULL)
  298. X                return(NULL);
  299. X
  300. X        /* Dig out information for optimizations. */
  301. X        r->regstart = '\0';     /* Worst-case defaults. */
  302. X        r->reganch = 0;
  303. X        r->regmust = NULL;
  304. X        r->regmlen = 0;
  305. X        scan = r->program+1;                    /* First BRANCH. */
  306. X        if (OP(regnext(scan)) == END) {         /* Only one top-level choice. */
  307. X                scan = OPERAND(scan);
  308. X
  309. X                /* Starting-point info. */
  310. X                if (OP(scan) == EXACTLY)
  311. X                        r->regstart = *OPERAND(scan);
  312. X                else if (OP(scan) == BOL)
  313. X                        r->reganch++;
  314. X
  315. X                /*
  316. X                 * If there's something expensive in the r.e., find the
  317. X                 * longest literal string that must appear and make it the
  318. X                 * regmust.  Resolve ties in favor of later strings, since
  319. X                 * the regstart check works with the beginning of the r.e.
  320. X                 * and avoiding duplication strengthens checking.  Not a
  321. X                 * strong reason, but sufficient in the absence of others.
  322. X                 */
  323. X                if (flags&SPSTART) {
  324. X                        longest = NULL;
  325. X                        len = 0;
  326. X                        for (; scan != NULL; scan = regnext(scan))
  327. X                                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  328. X                                        longest = OPERAND(scan);
  329. X                                        len = strlen(OPERAND(scan));
  330. X                                }
  331. X                        r->regmust = longest;
  332. X                        r->regmlen = len;
  333. X                }
  334. X        }
  335. X
  336. X        return(r);
  337. X}
  338. X
  339. X/*
  340. X - reg - regular expression, i.e. main body or parenthesized thing
  341. X *
  342. X * Caller must absorb opening parenthesis.
  343. X *
  344. X * Combining parenthesis handling with the base level of regular expression
  345. X * is a trifle forced, but the need to tie the tails of the branches to what
  346. X * follows makes it hard to avoid.
  347. X */
  348. X#ifdef __STDC__
  349. Xstatic char *reg (int paren, int *flagp)
  350. X#else
  351. Xstatic char *
  352. Xreg(paren, flagp)
  353. Xint paren;                      /* Parenthesized? */
  354. Xint *flagp;
  355. X#endif
  356. X{
  357. X        register char *ret;
  358. X        register char *br;
  359. X        register char *ender;
  360. X        register int parno;
  361. X        int flags;
  362. X
  363. X        *flagp = HASWIDTH;      /* Tentatively. */
  364. X
  365. X        /* Make an OPEN node, if parenthesized. */
  366. X        if (paren) {
  367. X                if (regnpar >= NSUBEXP)
  368. X                        FAIL("too many ()");
  369. X                parno = regnpar;
  370. X                regnpar++;
  371. X                ret = regnode(OPEN+parno);
  372. X        } else
  373. X                ret = NULL;
  374. X
  375. X        /* Pick up the branches, linking them together. */
  376. X        br = regbranch(&flags);
  377. X        if (br == NULL)
  378. X                return(NULL);
  379. X        if (ret != NULL)
  380. X                regtail(ret, br);       /* OPEN -> first. */
  381. X        else
  382. X                ret = br;
  383. X        if (!(flags&HASWIDTH))
  384. X                *flagp &= ~HASWIDTH;
  385. X        *flagp |= flags&SPSTART;
  386. X        while (*regparse == '|') {
  387. X                regparse++;
  388. X                br = regbranch(&flags);
  389. X                if (br == NULL)
  390. X                        return(NULL);
  391. X                regtail(ret, br);       /* BRANCH -> BRANCH. */
  392. X                if (!(flags&HASWIDTH))
  393. X                        *flagp &= ~HASWIDTH;
  394. X                *flagp |= flags&SPSTART;
  395. X        }
  396. X
  397. X        /* Make a closing node, and hook it on the end. */
  398. X        ender = regnode((paren) ? CLOSE+parno : END);
  399. X        regtail(ret, ender);
  400. X
  401. X        /* Hook the tails of the branches to the closing node. */
  402. X        for (br = ret; br != NULL; br = regnext(br))
  403. X                regoptail(br, ender);
  404. X
  405. X        /* Check for proper termination. */
  406. X        if (paren && *regparse++ != ')') {
  407. X                FAIL("unmatched ()");
  408. X        } else if (!paren && *regparse != '\0') {
  409. X                if (*regparse == ')') {
  410. X                        FAIL("unmatched ()");
  411. X                } else
  412. X                        FAIL("junk on end");    /* "Can't happen". */
  413. X                /* NOTREACHED */
  414. X        }
  415. X
  416. X        return(ret);
  417. X}
  418. X
  419. X/*
  420. X - regbranch - one alternative of an | operator
  421. X *
  422. X * Implements the concatenation operator.
  423. X */
  424. X#ifdef __STDC__
  425. Xstatic char *regbranch (int *flagp)
  426. X#else
  427. Xstatic char *
  428. Xregbranch(flagp)
  429. Xint *flagp;
  430. X#endif
  431. X{
  432. X        register char *ret;
  433. X        register char *chain;
  434. X        register char *latest;
  435. X        int flags;
  436. X
  437. X        *flagp = WORST;         /* Tentatively. */
  438. X
  439. X        ret = regnode(BRANCH);
  440. X        chain = NULL;
  441. X        while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  442. X                latest = regpiece(&flags);
  443. X                if (latest == NULL)
  444. X                        return(NULL);
  445. X                *flagp |= flags&HASWIDTH;
  446. X                if (chain == NULL)      /* First piece. */
  447. X                        *flagp |= flags&SPSTART;
  448. X                else
  449. X                        regtail(chain, latest);
  450. X                chain = latest;
  451. X        }
  452. X        if (chain == NULL)      /* Loop ran zero times. */
  453. X                (void) regnode(NOTHING);
  454. X
  455. X        return(ret);
  456. X}
  457. X
  458. X/*
  459. X - regpiece - something followed by possible [*+?]
  460. X *
  461. X * Note that the branching code sequences used for ? and the general cases
  462. X * of * and + are somewhat optimized:   they use the same NOTHING node as
  463. X * both the endmarker for their branch list and the body of the last branch.
  464. X * It might seem that this node could be dispensed with entirely, but the
  465. X * endmarker role is not redundant.
  466. X */
  467. X#ifdef __STDC__
  468. Xstatic char *regpiece (int *flagp)
  469. X#else
  470. Xstatic char *
  471. Xregpiece(flagp)
  472. Xint *flagp;
  473. X#endif
  474. X{
  475. X        register char *ret;
  476. X        register char op;
  477. X        register char *next;
  478. X        int flags;
  479. X
  480. X        ret = regatom(&flags);
  481. X        if (ret == NULL)
  482. X                return(NULL);
  483. X
  484. X        op = *regparse;
  485. X        if (!ISMULT(op)) {
  486. X                *flagp = flags;
  487. X                return(ret);
  488. X        }
  489. X
  490. X        if (!(flags&HASWIDTH) && op != '?')
  491. X                FAIL("*+ operand could be empty");
  492. X        *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
  493. X
  494. X        if (op == '*' && (flags&SIMPLE))
  495. X                reginsert(STAR, ret);
  496. X        else if (op == '*') {
  497. X                /* Emit x* as (x&|), where & means "self". */
  498. X                reginsert(BRANCH, ret);                 /* Either x */
  499. X                regoptail(ret, regnode(BACK));          /* and loop */
  500. X                regoptail(ret, ret);                    /* back */
  501. X                regtail(ret, regnode(BRANCH));          /* or */
  502. X                regtail(ret, regnode(NOTHING));         /* null. */
  503. X        } else if (op == '+' && (flags&SIMPLE))
  504. X                reginsert(PLUS, ret);
  505. X        else if (op == '+') {
  506. X                /* Emit x+ as x(&|), where & means "self". */
  507. X                next = regnode(BRANCH);                 /* Either */
  508. X                regtail(ret, next);
  509. X                regtail(regnode(BACK), ret);            /* loop back */
  510. X                regtail(next, regnode(BRANCH));         /* or */
  511. X                regtail(ret, regnode(NOTHING));         /* null. */
  512. X        } else if (op == '?') {
  513. X                /* Emit x? as (x|) */
  514. X                reginsert(BRANCH, ret);                 /* Either x */
  515. X                regtail(ret, regnode(BRANCH));          /* or */
  516. X                next = regnode(NOTHING);                /* null. */
  517. X                regtail(ret, next);
  518. X                regoptail(ret, next);
  519. X        }
  520. X        regparse++;
  521. X        if (ISMULT(*regparse))
  522. X                FAIL("nested *?+");
  523. X
  524. X        return(ret);
  525. X}
  526. X
  527. X/*
  528. X - regatom - the lowest level
  529. X *
  530. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  531. X * it can turn them into a single node, which is smaller to store and
  532. X * faster to run.  Backslashed characters are exceptions, each becoming a
  533. X * separate node; the code is simpler that way and it's not worth fixing.
  534. X */
  535. X#ifdef __STDC__
  536. Xstatic char *regatom (int *flagp)
  537. X#else
  538. Xstatic char *
  539. Xregatom(flagp)
  540. Xint *flagp;
  541. X#endif
  542. X{
  543. X        register char *ret;
  544. X        int flags;
  545. X
  546. X        *flagp = WORST;         /* Tentatively. */
  547. X
  548. X        switch (*regparse++) {
  549. X        case '^':
  550. X                ret = regnode(BOL);
  551. X                break;
  552. X        case '$':
  553. X                ret = regnode(EOL);
  554. X                break;
  555. X        case '.':
  556. X                ret = regnode(ANY);
  557. X                *flagp |= HASWIDTH|SIMPLE;
  558. X                break;
  559. X        case '[': {
  560. X                        register int class;
  561. X                        register int classend;
  562. X
  563. X                        if (*regparse == '^') { /* Complement of range. */
  564. X                                ret = regnode(ANYBUT);
  565. X                                regparse++;
  566. X                        } else
  567. X                                ret = regnode(ANYOF);
  568. X                        if (*regparse == ']' || *regparse == '-')
  569. X                                regc(*regparse++);
  570. X                        while (*regparse != '\0' && *regparse != ']') {
  571. X                                if (*regparse == '-') {
  572. X                                        regparse++;
  573. X                                        if (*regparse == ']' || *regparse == '\0')
  574. X                                                regc('-');
  575. X                                        else {
  576. X                                                class = UCHARAT(regparse-2)+1;
  577. X                                                classend = UCHARAT(regparse);
  578. X                                                if (class > classend+1)
  579. X                                                        FAIL("invalid [] range");
  580. X                                                for (; class <= classend; class++)
  581. X                                                        regc(class);
  582. X                                                regparse++;
  583. X                                        }
  584. X                                } else
  585. X                                        regc(*regparse++);
  586. X                        }
  587. X                        regc('\0');
  588. X                        if (*regparse != ']')
  589. X                                FAIL("unmatched []");
  590. X                        regparse++;
  591. X                        *flagp |= HASWIDTH|SIMPLE;
  592. X                }
  593. X                break;
  594. X        case '(':
  595. X                ret = reg(1, &flags);
  596. X                if (ret == NULL)
  597. X                        return(NULL);
  598. X                *flagp |= flags&(HASWIDTH|SPSTART);
  599. X                break;
  600. X        case '\0':
  601. X        case '|':
  602. X        case ')':
  603. X                FAIL("internal urp");   /* Supposed to be caught earlier. */
  604. X                break;
  605. X        case '?':
  606. X        case '+':
  607. X        case '*':
  608. X                FAIL("?+* follows nothing");
  609. X                break;
  610. X        case '\\':
  611. X                if (*regparse == '\0')
  612. X                        FAIL("trailing \\");
  613. X                ret = regnode(EXACTLY);
  614. X                regc(*regparse++);
  615. X                regc('\0');
  616. X                *flagp |= HASWIDTH|SIMPLE;
  617. X                break;
  618. X        default: {
  619. X                        register int len;
  620. X                        register char ender;
  621. X
  622. X                        regparse--;
  623. X                        len = strcspn(regparse, META);
  624. X                        if (len <= 0)
  625. X                                FAIL("internal disaster");
  626. X                        ender = *(regparse+len);
  627. X                        if (len > 1 && ISMULT(ender))
  628. X                                len--;          /* Back off clear of ?+* operand. */
  629. X                        *flagp |= HASWIDTH;
  630. X                        if (len == 1)
  631. X                                *flagp |= SIMPLE;
  632. X                        ret = regnode(EXACTLY);
  633. X                        while (len > 0) {
  634. X                                regc(*regparse++);
  635. X                                len--;
  636. X                        }
  637. X                        regc('\0');
  638. X                }
  639. X                break;
  640. X        }
  641. X
  642. X        return(ret);
  643. X}
  644. X
  645. X/*
  646. X - regnode - emit a node
  647. X */
  648. X#ifdef __STDC__
  649. Xstatic char *regnode (char op)
  650. X#else
  651. Xstatic char *                   /* Location. */
  652. Xregnode(op)
  653. Xchar op;
  654. X#endif
  655. X{
  656. X        register char *ret;
  657. X        register char *ptr;
  658. X
  659. X        ret = regcode;
  660. X        if (ret == ®dummy) {
  661. X                regsize += 3;
  662. X                return(ret);
  663. X        }
  664. X
  665. X        ptr = ret;
  666. X        *ptr++ = op;
  667. X        *ptr++ = '\0';          /* Null "next" pointer. */
  668. X        *ptr++ = '\0';
  669. X        regcode = ptr;
  670. X
  671. X        return(ret);
  672. X}
  673. X
  674. X/*
  675. X - regc - emit (if appropriate) a byte of code
  676. X */
  677. X#ifdef __STDC__
  678. Xstatic void regc (char b)
  679. X#else
  680. Xstatic void
  681. Xregc(b)
  682. Xchar b;
  683. X#endif
  684. X{
  685. X        if (regcode != ®dummy)
  686. X                *regcode++ = b;
  687. X        else
  688. X                regsize++;
  689. X}
  690. X
  691. X/*
  692. X - reginsert - insert an operator in front of already-emitted operand
  693. X *
  694. X * Means relocating the operand.
  695. X */
  696. X#ifdef __STDC__
  697. Xstatic void reginsert (char op, char *opnd)
  698. X#else
  699. Xstatic void
  700. Xreginsert(op, opnd)
  701. Xchar op;
  702. Xchar *opnd;
  703. X#endif
  704. X{
  705. X        register char *src;
  706. X        register char *dst;
  707. X        register char *place;
  708. X
  709. X        if (regcode == ®dummy) {
  710. X                regsize += 3;
  711. X                return;
  712. X        }
  713. X
  714. X        src = regcode;
  715. X        regcode += 3;
  716. X        dst = regcode;
  717. X        while (src > opnd)
  718. X                *--dst = *--src;
  719. X
  720. X        place = opnd;           /* Op node, where operand used to be. */
  721. X        *place++ = op;
  722. X        *place++ = '\0';
  723. X        *place++ = '\0';
  724. X}
  725. X
  726. X/*
  727. X - regtail - set the next-pointer at the end of a node chain
  728. X */
  729. X#ifdef __STDC__
  730. Xstatic void regtail (char *p, char *val)
  731. X#else
  732. Xstatic void
  733. Xregtail(p, val)
  734. Xchar *p;
  735. Xchar *val;
  736. X#endif
  737. X{
  738. X        register char *scan;
  739. X        register char *temp;
  740. X        register int offset;
  741. X
  742. X        if (p == ®dummy)
  743. X                return;
  744. X
  745. X        /* Find last node. */
  746. X        scan = p;
  747. X        for (;;) {
  748. X                temp = regnext(scan);
  749. X                if (temp == NULL)
  750. X                        break;
  751. X                scan = temp;
  752. X        }
  753. X
  754. X        if (OP(scan) == BACK)
  755. X                offset = scan - val;
  756. X        else
  757. X                offset = val - scan;
  758. X        *(scan+1) = (offset>>8)&0377;
  759. X        *(scan+2) = offset&0377;
  760. X}
  761. X
  762. X/*
  763. X - regoptail - regtail on operand of first argument; nop if operandless
  764. X */
  765. X#ifdef __STDC__
  766. Xstatic void regoptail (char *p, char *val)
  767. X#else
  768. Xstatic void
  769. Xregoptail(p, val)
  770. Xchar *p;
  771. Xchar *val;
  772. X#endif
  773. X{
  774. X        /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  775. X        if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  776. X                return;
  777. X        regtail(OPERAND(p), val);
  778. X}
  779. X
  780. X/*
  781. X * regexec and friends
  782. X */
  783. X
  784. X/*
  785. X * Global work variables for regexec().
  786. X */
  787. Xstatic char *reginput;  /* String-input pointer. */
  788. Xstatic char *regbol;            /* Beginning of input, for ^ check. */
  789. Xstatic char **regstartp;        /* Pointer to startp array. */
  790. Xstatic char **regendp;  /* Ditto for endp. */
  791. X
  792. X/*
  793. X * Forwards.
  794. X */
  795. XSTATIC int regtry();
  796. XSTATIC int regmatch();
  797. XSTATIC int regrepeat();
  798. X
  799. X#ifdef DEBUG
  800. Xint regnarrate = 0;
  801. Xvoid regdump();
  802. XSTATIC char *regprop();
  803. X#endif
  804. X
  805. X/*
  806. X - regexec - match a regexp against a string
  807. X */
  808. X#ifdef __STDC__
  809. Xint regexec (register regexp *prog, register char *string)
  810. X#else
  811. Xint
  812. Xregexec(prog, string)
  813. Xregister regexp *prog;
  814. Xregister char *string;
  815. X#endif
  816. X{
  817. X        register char *s;
  818. X        extern char *strchr();
  819. X
  820. X        /* Be paranoid... */
  821. X        if (prog == NULL || string == NULL) {
  822. X                regerror("NULL parameter");
  823. X                return(0);
  824. X        }
  825. X
  826. X        /* Check validity of program. */
  827. X        if (UCHARAT(prog->program) != MAGIC) {
  828. X                regerror("corrupted program");
  829. X                return(0);
  830. X        }
  831. X
  832. X        /* If there is a "must appear" string, look for it. */
  833. X        if (prog->regmust != NULL) {
  834. X                s = string;
  835. X                while ((s = strchr(s, prog->regmust[0])) != NULL) {
  836. X                        if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  837. X                                break;  /* Found it. */
  838. X                        s++;
  839. X                }
  840. X                if (s == NULL)  /* Not present. */
  841. X                        return(0);
  842. X        }
  843. X
  844. X        /* Mark beginning of line for ^ . */
  845. X        regbol = string;
  846. X
  847. X        /* Simplest case:  anchored match need be tried only once. */
  848. X        if (prog->reganch)
  849. X                return(regtry(prog, string));
  850. X
  851. X        /* Messy cases:  unanchored match. */
  852. X        s = string;
  853. X        if (prog->regstart != '\0')
  854. X                /* We know what char it must start with. */
  855. X                while ((s = strchr(s, prog->regstart)) != NULL) {
  856. X                        if (regtry(prog, s))
  857. X                                return(1);
  858. X                        s++;
  859. X                }
  860. X        else
  861. X                /* We don't -- general case. */
  862. X                do {
  863. X                        if (regtry(prog, s))
  864. X                                return(1);
  865. X                } while (*s++ != '\0');
  866. X
  867. X        /* Failure. */
  868. X        return(0);
  869. X}
  870. X
  871. X/*
  872. X - regtry - try match at specific point
  873. X */
  874. X#ifdef __STDC__
  875. Xstatic int regtry (regexp *prog, char *string)
  876. X#else
  877. Xstatic int                      /* 0 failure, 1 success */
  878. Xregtry(prog, string)
  879. Xregexp *prog;
  880. Xchar *string;
  881. X#endif
  882. X{
  883. X        register int i;
  884. X        register char **sp;
  885. X        register char **ep;
  886. X
  887. X        reginput = string;
  888. X        regstartp = prog->startp;
  889. X        regendp = prog->endp;
  890. X
  891. X        sp = prog->startp;
  892. X        ep = prog->endp;
  893. X        for (i = NSUBEXP; i > 0; i--) {
  894. X                *sp++ = NULL;
  895. X                *ep++ = NULL;
  896. X        }
  897. X        if (regmatch(prog->program + 1)) {
  898. X                prog->startp[0] = string;
  899. X                prog->endp[0] = reginput;
  900. X                return(1);
  901. X        } else
  902. X                return(0);
  903. X}
  904. X
  905. X/*
  906. X - regmatch - main matching routine
  907. X *
  908. X * Conceptually the strategy is simple:  check to see whether the current
  909. X * node matches, call self recursively to see whether the rest matches,
  910. X * and then act accordingly.  In practice we make some effort to avoid
  911. X * recursion, in particular by going through "ordinary" nodes (that don't
  912. X * need to know whether the rest of the match failed) by a loop instead of
  913. X * by recursion.
  914. X */
  915. X#ifdef __STDC__
  916. Xstatic int regmatch (char *prog)
  917. X#else
  918. Xstatic int                      /* 0 failure, 1 success */
  919. Xregmatch(prog)
  920. Xchar *prog;
  921. X#endif
  922. X{
  923. X        register char *scan;    /* Current node. */
  924. X        char *next;             /* Next node. */
  925. X        extern char *strchr();
  926. X
  927. X        scan = prog;
  928. X#ifdef DEBUG
  929. X        if (scan != NULL && regnarrate)
  930. X                fprintf(stderr, "%s(\n", regprop(scan));
  931. X#endif
  932. X        while (scan != NULL) {
  933. X#ifdef DEBUG
  934. X                if (regnarrate)
  935. X                        fprintf(stderr, "%s...\n", regprop(scan));
  936. X#endif
  937. X                next = regnext(scan);
  938. X
  939. X                switch (OP(scan)) {
  940. X                case BOL:
  941. X                        if (reginput != regbol)
  942. X                                return(0);
  943. X                        break;
  944. X                case EOL:
  945. X                        if (*reginput != '\0')
  946. X                                return(0);
  947. X                        break;
  948. X                case ANY:
  949. X                        if (*reginput == '\0')
  950. X                                return(0);
  951. X                        reginput++;
  952. X                        break;
  953. X                case EXACTLY: {
  954. X                                register int len;
  955. X                                register char *opnd;
  956. X
  957. X                                opnd = OPERAND(scan);
  958. X                                /* Inline the first character, for speed. */
  959. X                                if (*opnd != *reginput)
  960. X                                        return(0);
  961. X                                len = strlen(opnd);
  962. X                                if (len > 1 && strncmp(opnd, reginput, len) != 0)
  963. X                                        return(0);
  964. X                                reginput += len;
  965. X                        }
  966. X                        break;
  967. X                case ANYOF:
  968. X                        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  969. X                                return(0);
  970. X                        reginput++;
  971. X                        break;
  972. X                case ANYBUT:
  973. X                        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  974. X                                return(0);
  975. X                        reginput++;
  976. X                        break;
  977. X                case NOTHING:
  978. X                        break;
  979. X                case BACK:
  980. X                        break;
  981. X                case OPEN+1:
  982. X                case OPEN+2:
  983. X                case OPEN+3:
  984. X                case OPEN+4:
  985. X                case OPEN+5:
  986. X                case OPEN+6:
  987. X                case OPEN+7:
  988. X                case OPEN+8:
  989. X                case OPEN+9: {
  990. X                                register int no;
  991. X                                register char *save;
  992. X
  993. X                                no = OP(scan) - OPEN;
  994. X                                save = reginput;
  995. X
  996. X                                if (regmatch(next)) {
  997. X                                        /*
  998. X                                         * Don't set startp if some later
  999. X                                         * invocation of the same parentheses
  1000. X                                         * already has.
  1001. X                                         */
  1002. X                                        if (regstartp[no] == NULL)
  1003. X                                                regstartp[no] = save;
  1004. X                                        return(1);
  1005. X                                } else
  1006. X                                        return(0);
  1007. X                        }
  1008. X                        break;
  1009. X                case CLOSE+1:
  1010. X                case CLOSE+2:
  1011. X                case CLOSE+3:
  1012. X                case CLOSE+4:
  1013. X                case CLOSE+5:
  1014. X                case CLOSE+6:
  1015. X                case CLOSE+7:
  1016. X                case CLOSE+8:
  1017. X                case CLOSE+9: {
  1018. X                                register int no;
  1019. X                                register char *save;
  1020. X
  1021. X                                no = OP(scan) - CLOSE;
  1022. X                                save = reginput;
  1023. X
  1024. X                                if (regmatch(next)) {
  1025. X                                        /*
  1026. X                                         * Don't set endp if some later
  1027. X                                         * invocation of the same parentheses
  1028. X                                         * already has.
  1029. X                                         */
  1030. X                                        if (regendp[no] == NULL)
  1031. X                                                regendp[no] = save;
  1032. X                                        return(1);
  1033. X                                } else
  1034. X                                        return(0);
  1035. X                        }
  1036. X                        break;
  1037. X                case BRANCH: {
  1038. X                                register char *save;
  1039. X
  1040. X                                if (OP(next) != BRANCH)         /* No choice. */
  1041. X                                        next = OPERAND(scan);   /* Avoid recursion. */
  1042. X                                else {
  1043. X                                        do {
  1044. X                                                save = reginput;
  1045. X                                                if (regmatch(OPERAND(scan)))
  1046. X                                                        return(1);
  1047. X                                                reginput = save;
  1048. X                                                scan = regnext(scan);
  1049. X                                        } while (scan != NULL && OP(scan) == BRANCH);
  1050. X                                        return(0);
  1051. X                                        /* NOTREACHED */
  1052. X                                }
  1053. X                        }
  1054. X                        break;
  1055. X                case STAR:
  1056. X                case PLUS: {
  1057. X                                register char nextch;
  1058. X                                register int no;
  1059. X                                register char *save;
  1060. X                                register int min;
  1061. X
  1062. X                                /*
  1063. X                                 * Lookahead to avoid useless match attempts
  1064. X                                 * when we know what character comes next.
  1065. X                                 */
  1066. X                                nextch = '\0';
  1067. X                                if (OP(next) == EXACTLY)
  1068. X                                        nextch = *OPERAND(next);
  1069. X                                min = (OP(scan) == STAR) ? 0 : 1;
  1070. X                                save = reginput;
  1071. X                                no = regrepeat(OPERAND(scan));
  1072. X                                while (no >= min) {
  1073. X                                        /* If it could work, try it. */
  1074. X                                        if (nextch == '\0' || *reginput == nextch)
  1075. X                                                if (regmatch(next))
  1076. X                                                        return(1);
  1077. X                                        /* Couldn't or didn't -- back up. */
  1078. X                                        no--;
  1079. X                                        reginput = save + no;
  1080. X                                }
  1081. X                                return(0);
  1082. X                        }
  1083. X                        break;
  1084. X                case END:
  1085. X                        return(1);      /* Success! */
  1086. X                        break;
  1087. X                default:
  1088. X                        regerror("memory corruption");
  1089. X                        return(0);
  1090. X                        break;
  1091. X                }
  1092. X
  1093. X                scan = next;
  1094. X        }
  1095. X
  1096. X        /*
  1097. X         * We get here only if there's trouble -- normally "case END" is
  1098. X         * the terminating point.
  1099. X         */
  1100. X        regerror("corrupted pointers");
  1101. X        return(0);
  1102. X}
  1103. X
  1104. X/*
  1105. X - regrepeat - repeatedly match something simple, report how many
  1106. X */
  1107. X#ifdef __STDC__
  1108. Xstatic int regrepeat (char *p)
  1109. X#else
  1110. Xstatic int
  1111. Xregrepeat(p)
  1112. Xchar *p;
  1113. X#endif
  1114. X{
  1115. X        register int count = 0;
  1116. X        register char *scan;
  1117. X        register char *opnd;
  1118. X
  1119. X        scan = reginput;
  1120. X        opnd = OPERAND(p);
  1121. X        switch (OP(p)) {
  1122. X        case ANY:
  1123. X                count = strlen(scan);
  1124. X                scan += count;
  1125. X                break;
  1126. X        case EXACTLY:
  1127. X                while (*opnd == *scan) {
  1128. X                        count++;
  1129. X                        scan++;
  1130. X                }
  1131. X                break;
  1132. X        case ANYOF:
  1133. X                while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  1134. X                        count++;
  1135. X                        scan++;
  1136. X                }
  1137. X                break;
  1138. X        case ANYBUT:
  1139. X                while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  1140. X                        count++;
  1141. X                        scan++;
  1142. X                }
  1143. X                break;
  1144. X        default:                /* Oh dear.  Called inappropriately. */
  1145. X                regerror("internal foulup");
  1146. X                count = 0;      /* Best compromise. */
  1147. X                break;
  1148. X        }
  1149. X        reginput = scan;
  1150. X
  1151. X        return(count);
  1152. X}
  1153. X
  1154. X/*
  1155. X - regnext - dig the "next" pointer out of a node
  1156. X */
  1157. X#ifdef __STDC__
  1158. Xstatic char *regnext (register char *p)
  1159. X#else
  1160. Xstatic char *
  1161. Xregnext(p)
  1162. Xregister char *p;
  1163. X#endif
  1164. X{
  1165. X        register int offset;
  1166. X
  1167. X        if (p == ®dummy)
  1168. X                return(NULL);
  1169. X
  1170. X        offset = NEXT(p);
  1171. X        if (offset == 0)
  1172. X                return(NULL);
  1173. X
  1174. X        if (OP(p) == BACK)
  1175. X                return(p-offset);
  1176. X        else
  1177. X                return(p+offset);
  1178. X}
  1179. X
  1180. X#ifdef DEBUG
  1181. X
  1182. XSTATIC char *regprop();
  1183. X
  1184. X/*
  1185. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  1186. X */
  1187. Xvoid
  1188. Xregdump(r)
  1189. Xregexp *r;
  1190. X{
  1191. X        register char *s;
  1192. X        register char op = EXACTLY;     /* Arbitrary non-END op. */
  1193. X        register char *next;
  1194. X        extern char *strchr();
  1195. X
  1196. X
  1197. X        s = r->program + 1;
  1198. X        while (op != END) {     /* While that wasn't END last time... */
  1199. X                op = OP(s);
  1200. X                printf("%2d%s", s-r->program, regprop(s));      /* Where, what. */
  1201. X                next = regnext(s);
  1202. X                if (next == NULL)               /* Next ptr. */
  1203. X                        printf("(0)");
  1204. X                else
  1205. X                        printf("(%d)", (s-r->program)+(next-s));
  1206. X                s += 3;
  1207. X                if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  1208. X                        /* Literal string, where present. */
  1209. X                        while (*s != '\0') {
  1210. X                                putchar(*s);
  1211. X                                s++;
  1212. X                        }
  1213. X                        s++;
  1214. X                }
  1215. X                putchar('\n');
  1216. X        }
  1217. X
  1218. X        /* Header fields of interest. */
  1219. X        if (r->regstart != '\0')
  1220. X                printf("start `%c' ", r->regstart);
  1221. X        if (r->reganch)
  1222. X                printf("anchored ");
  1223. X        if (r->regmust != NULL)
  1224. X                printf("must have \"%s\"", r->regmust);
  1225. X        printf("\n");
  1226. X}
  1227. X
  1228. X/*
  1229. X - regprop - printable representation of opcode
  1230. X */
  1231. Xstatic char *
  1232. Xregprop(op)
  1233. Xchar *op;
  1234. X{
  1235. X        register char *p;
  1236. X        static char buf[50];
  1237. X
  1238. X        (void) strcpy(buf, ":");
  1239. X
  1240. X        switch (OP(op)) {
  1241. X        case BOL:
  1242. X                p = "BOL";
  1243. X                break;
  1244. X        case EOL:
  1245. X                p = "EOL";
  1246. X                break;
  1247. X        case ANY:
  1248. X                p = "ANY";
  1249. X                break;
  1250. X        case ANYOF:
  1251. X                p = "ANYOF";
  1252. X                break;
  1253. X        case ANYBUT:
  1254. X                p = "ANYBUT";
  1255. X                break;
  1256. X        case BRANCH:
  1257. X                p = "BRANCH";
  1258. X                break;
  1259. X        case EXACTLY:
  1260. X                p = "EXACTLY";
  1261. X                break;
  1262. X        case NOTHING:
  1263. X                p = "NOTHING";
  1264. X                break;
  1265. X        case BACK:
  1266. X                p = "BACK";
  1267. X                break;
  1268. X        case END:
  1269. X                p = "END";
  1270. X                break;
  1271. X        case OPEN+1:
  1272. X        case OPEN+2:
  1273. X        case OPEN+3:
  1274. X        case OPEN+4:
  1275. X        case OPEN+5:
  1276. X        case OPEN+6:
  1277. X        case OPEN+7:
  1278. X        case OPEN+8:
  1279. X        case OPEN+9:
  1280. X                sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
  1281. X                p = NULL;
  1282. X                break;
  1283. X        case CLOSE+1:
  1284. X        case CLOSE+2:
  1285. X        case CLOSE+3:
  1286. X        case CLOSE+4:
  1287. X        case CLOSE+5:
  1288. X        case CLOSE+6:
  1289. X        case CLOSE+7:
  1290. X        case CLOSE+8:
  1291. X        case CLOSE+9:
  1292. X                sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
  1293. X                p = NULL;
  1294. X                break;
  1295. X        case STAR:
  1296. X                p = "STAR";
  1297. X                break;
  1298. X        case PLUS:
  1299. X                p = "PLUS";
  1300. X                break;
  1301. X        default:
  1302. X                regerror("corrupted opcode");
  1303. X                break;
  1304. X        }
  1305. X        if (p != NULL)
  1306. X                (void) strcat(buf, p);
  1307. X        return(buf);
  1308. X}
  1309. X#endif
  1310. X
  1311. X/*
  1312. X * The following is provided for those people who do not have strcspn() in
  1313. X * their C libraries.   They should get off their butts and do something
  1314. X * about it; at least one public-domain implementation of those (highly
  1315. X * useful) string routines has been published on Usenet.
  1316. X */
  1317. X#ifdef STRCSPN
  1318. X/*
  1319. X * strcspn - find length of initial segment of s1 consisting entirely
  1320. X * of characters not from s2
  1321. X */
  1322. X
  1323. Xstatic int
  1324. Xstrcspn(s1, s2)
  1325. Xchar *s1;
  1326. Xchar *s2;
  1327. X{
  1328. X        register char *scan1;
  1329. X        register char *scan2;
  1330. X        register int count;
  1331. X
  1332. X        count = 0;
  1333. X        for (scan1 = s1; *scan1 != '\0'; scan1++) {
  1334. X                for (scan2 = s2; *scan2 != '\0';)       /* ++ moved down. */
  1335. X                        if (*scan1 == *scan2++)
  1336. X                                return(count);
  1337. X                count++;
  1338. X        }
  1339. X        return(count);
  1340. X}
  1341. X#endif
  1342. END_OF_FILE
  1343. if test 41694 -ne `wc -c <'Less1.4Z/src/regexp.c'`; then
  1344.     echo shar: \"'Less1.4Z/src/regexp.c'\" unpacked with wrong size!
  1345. fi
  1346. # end of 'Less1.4Z/src/regexp.c'
  1347. fi
  1348. echo shar: End of archive 6 \(of 7\).
  1349. cp /dev/null ark6isdone
  1350. MISSING=""
  1351. for I in 1 2 3 4 5 6 7 ; do
  1352.     if test ! -f ark${I}isdone ; then
  1353.     MISSING="${MISSING} ${I}"
  1354.     fi
  1355. done
  1356. if test "${MISSING}" = "" ; then
  1357.     echo You have unpacked all 7 archives.
  1358.     rm -f ark[1-9]isdone
  1359. else
  1360.     echo You still need to unpack the following archives:
  1361.     echo "        " ${MISSING}
  1362. fi
  1363. ##  End of shell archive.
  1364. exit 0
  1365. -- 
  1366. Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
  1367. Mail comments to the moderator at <amiga-request@uunet.uu.net>.
  1368. Post requests for sources, and general discussion to comp.sys.amiga.misc.
  1369.